<template>
  <div class="custom-mention" ref="container">
    <div v-stop-comfy-events class="mention-editor" contenteditable @input="handleInput" @keydown="handleKeyDown" @focus="handleFocus"
      @blur="handleBlur" ref="editor"></div>
    <el-popover
      v-if="filteredOptions.length > 0"
      ref="popoverRef"
      v-model:visible="showSuggestions"
      :virtual-ref="virtualTrigger"
      trigger="manual"
      :offset="5"
      placement="bottom-start"
      popper-class="mention-popper"
      :append-to-body="true"
      :gpu-acceleration="false"
      transition="el-zoom-in-top"
      :persistent="true"
      manual-mode
      :width="300"
    >
      <template #default>
        <div class="mention-suggestions" >
          <template v-if="loading">
            <div class="loading-text">
              <el-icon class="is-loading"><Loading /></el-icon>
              {{ $t('common.loading') }}
            </div>
          </template>
          <template v-else>
            <div
              v-for="(item, index) in filteredOptions"
              :key="item.value"
              class="suggestion-item"
              :class="{ 'is-active': index === activeIndex }"
              @click="selectItem(item)"
              @mousedown.prevent="handleMouseDown"
            >
              <div class="suggestion-content">
                <el-avatar
                  :src="getProcessedImageUrl(item.name)"
                  size="default"
                  class="avatar"
                  @error="handleImageError"
                >
                  <template #default>
                    <el-icon><User /></el-icon>
                  </template>
                </el-avatar>
                <div class="info">
                  <span class="value">{{ item.value }}</span>
                  <span class="label">{{ item.label }}</span>
                </div>
              </div>
            </div>
          </template>
        </div>
      </template>
    </el-popover>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick, shallowRef, onBeforeUnmount } from 'vue'
import { debounce } from 'lodash-es'
import { useConfigStore } from '@renderer/stores/configStore'

const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  options: {
    type: Array,
    default: () => []
  },
  remoteMethod: {
    type: Function,
    default: null
  },
  triggerChars: {
    type: Array,
    default: () => ['@', ',']
  },
  debounce: {
    type: Number,
    default: 150
  },
  maxVisibleOptions: {
    type: Number,
    default: 50
  },
  appendComma: {
    type: Boolean,
    default: true
  },
  preserveWhitespace: {
    type: Boolean,
    default: true
  },
  requireTrigger: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['update:modelValue', 'select', 'change', 'clear'])

const configStore = useConfigStore();

// 响应式状态
const showSuggestions = ref(false)
const searchQuery = ref('')
const searchPrefix = ref('')
const activeIndex = ref(-1)
const loading = ref(false)
const lastCursorPos = ref(0)
const editor = ref<HTMLElement | null>(null)
const container = ref<HTMLElement | null>(null)
const popoverRef = shallowRef<any>(null)

// 新增：跟踪输入框是否为空状态
const isInputEmpty = ref(true)

// 虚拟触发器用于定位
const virtualTrigger = ref({
  getBoundingClientRect: () => ({
    top: cursorPosition.value.top,
    left: cursorPosition.value.left,
    bottom: cursorPosition.value.top + 5,
    right: cursorPosition.value.left + 5,
    width: 1,
    height: 1
  })
})

// 光标位置
const cursorPosition = ref({
  top: 0,
  left: 0
})

const filteredOptions = computed(() => {
  return props.options.slice(0, props.maxVisibleOptions)
})

const sanitizeFilename = (name: string) => {
  return name ? name.replace(/[/\\?%*:|"<>]/g, '_') : 'untitled';
};

const getProcessedImageUrl = (name: string) => {
  if (!name) return '';
  const imageName = sanitizeFilename(name);
  return configStore.comfyProxyImage(`file://${configStore.config.imagesPath}/character/${imageName}.webp`);
}

// 焦点追踪状态
const isEditorFocused = ref(false);

const updateCursorPosition = () => {
  requestAnimationFrame(() => {
    const selection = window.getSelection();
    if (!selection || selection.rangeCount === 0) return;

    const range = selection.getRangeAt(0);

    try {
      // 创建临时标记获取精确位置
      const marker = document.createElement('span');
      marker.textContent = '\u200b';
      marker.style.cssText = 'position: absolute; visibility: hidden; pointer-events: none;';
      range.insertNode(marker);

      const markerRect = marker.getBoundingClientRect();
      cursorPosition.value = {
        top: markerRect.bottom + window.scrollY,
        left: markerRect.left + window.scrollX
      };

      marker.parentNode?.removeChild(marker);

    } catch (error) {
      console.error('Failed to update cursor position:', error);
    }
  });
};

// 事件处理
const handleFocus = () => {
  isEditorFocused.value = true;
};

const handleMouseDown = (e: Event) => {
  e.preventDefault();
  e.stopPropagation();
}

const handleBlur = () => {
  setTimeout(() => {
    if (!document.activeElement?.closest('.mention-popper')) {
      showSuggestions.value = false;
    }
  }, 200);
};

// 改进输入处理：精确判断输入框为空状态
const handleInput = (event: Event) => {
  Promise.resolve().then(() => {
    const target = event.target as HTMLElement;
    // 精确判断输入框是否为空：textContent未定义或为空字符串
    const textContent = target.textContent;
    isInputEmpty.value = !textContent || textContent.trim() === '';
    
    let text = textContent || '';

    // 同步到modelValue
    if (text !== props.modelValue) {
      emit('update:modelValue', text);
    }

    const cursorPos = getCursorPosition(target);
    const inputContent = text.slice(0, cursorPos); // 光标前的所有内容
    
    // 查找最近的触发字符
    let closestTrigger = null;
    let searchIndex = cursorPos - 1;
    
    while (searchIndex >= 0) {
      const char = text[searchIndex];
      if (props.triggerChars.includes(char)) {
        closestTrigger = {
          char,
          index: searchIndex
        };
        break;
      }
      searchIndex--;
    }

    // 情况1: 需要触发字符才能检索 (requireTrigger为true)
    if (props.requireTrigger) {
      if (closestTrigger) {
        const { char, index } = closestTrigger;
        const query = text.slice(index + 1, cursorPos);
        
        if (query.length > 0) {
          batchUpdate(() => {
            showSuggestions.value = true;
            searchPrefix.value = char;
            lastCursorPos.value = index;
            searchQuery.value = query;
          });
          updateCursorPosition();
        } else {
          showSuggestions.value = false;
          searchQuery.value = '';
        }
      } else {
        showSuggestions.value = false;
        searchQuery.value = '';
      }
    } 
    // 情况2: 不需要触发字符，空输入框输入直接检索 (requireTrigger为false)
    else {
      // 如果有触发字符，优先使用触发字符后的内容
      if (closestTrigger) {
        const { char, index } = closestTrigger;
        const query = text.slice(index + 1, cursorPos);
        
        if (query.length > 0) {
          batchUpdate(() => {
            showSuggestions.value = true;
            searchPrefix.value = char;
            lastCursorPos.value = index;
            searchQuery.value = query;
          });
          updateCursorPosition();
          return;
        }
      }
      
      // 没有触发字符或触发字符后无内容，使用光标前的所有内容作为查询
      if (inputContent.length > 0) {
        batchUpdate(() => {
          showSuggestions.value = true;
          searchPrefix.value = '';
          lastCursorPos.value = 0;
          searchQuery.value = inputContent;
        });
        updateCursorPosition();
      } else {
        showSuggestions.value = false;
        searchQuery.value = '';
      }
    }
  });
};

// 批处理更新函数
const batchUpdate = (callback: () => void) => {
  const ctx = (window as any).__VUE__;
  if (ctx && ctx.runWithContext) {
    ctx.runWithContext(callback);
  } else {
    callback();
  }
};

const getCursorPosition = (editorEl: HTMLElement): number => {
  const selection = window.getSelection();
  if (!selection || selection.rangeCount === 0) return 0;

  const range = selection.getRangeAt(0);
  const preCaretRange = range.cloneRange();
  preCaretRange.selectNodeContents(editorEl);
  preCaretRange.setEnd(range.endContainer, range.endOffset);

  return preCaretRange.toString().length;
};

// 键盘处理
const handleKeyDown = (event: KeyboardEvent) => {
  if (!showSuggestions.value) return;

  switch (event.key) {
    case 'ArrowUp':
      event.preventDefault();
      activeIndex.value = Math.max(0, activeIndex.value - 1);
      nextTick(scrollToActiveItem);
      break;
    case 'ArrowDown':
      event.preventDefault();
      activeIndex.value = Math.min(
        filteredOptions.value.length - 1,
        activeIndex.value + 1
      );
      nextTick(scrollToActiveItem);
      break;
    case 'Enter':
      event.preventDefault();
      if (activeIndex.value >= 0) {
        selectItem(filteredOptions.value[activeIndex.value]);
      }
      break;
    case 'Escape':
      showSuggestions.value = false;
      break;
    case 'Tab':
      if (activeIndex.value >= 0) {
        event.preventDefault();
        selectItem(filteredOptions.value[activeIndex.value]);
      }
      break;
  }
}

const scrollToActiveItem = () => {
  const popperEl = document.querySelector('.mention-popper');
  const activeEl = popperEl?.querySelector('.is-active');

  if (activeEl) {
    activeEl.scrollIntoView({
      block: 'nearest',
      behavior: 'instant'
    });
  }
}

// 搜索方法
const debouncedSearch = debounce((query) => {
  if (props.remoteMethod) {
    loading.value = true;
    props.remoteMethod(query, searchPrefix.value).finally(() => {
      loading.value = false;
    });
  }
}, props.debounce);

watch(searchQuery, (newVal) => {
  if (newVal) {
    debouncedSearch(newVal);
  }
});

// 选择项目 - 针对空输入框状态添加特殊处理
const selectItem = (item) => {
  if (!editor.value) return;

  let text = editor.value.textContent || '';
  let newText;
  let newCursorPos;
  
  // 关键修改：处理输入框为空的特殊情况
  if (isInputEmpty.value) {
    // 输入框为空时，直接填充内容并添加逗号
    newText = `${item.value},`;
    // 光标位置设置到末尾
    newCursorPos = newText.length;
  } 
  // 有触发词的情况：替换触发词后的内容
  else if (searchPrefix.value) {
    const before = text.slice(0, lastCursorPos.value);
    const after = text.slice(lastCursorPos.value + 1 + searchQuery.value.length);
    const beforeItem = ','
    const separator = after === "" ? ',' : '';
    newText = `${before}${beforeItem}${item.value}${separator}${after}`;
    newCursorPos = lastCursorPos.value + 1 + item.value.length + (after === "" ? 1 : 0);
  } 
  // 无触发词的情况：替换整个查询内容
  else {
    const separator = ','; // 添加空格分隔
    newText = `${item.value}${separator}`;
    newCursorPos = item.value.length + 1;
  }

  editor.value.textContent = newText;

  // 设置光标到新位置
  setCursorPosition(editor.value, newCursorPos);

  // 重置状态
  showSuggestions.value = false;
  searchQuery.value = '';
  activeIndex.value = -1;
  isInputEmpty.value = false; // 选择项目后输入框不再为空

  // 触发更新事件
  emit('update:modelValue', newText);
  emit('select', item);

  // 确保编辑器保持焦点
  editor.value.focus();
}

// 设置光标位置
const setCursorPosition = (el: HTMLElement, position: number) => {
  nextTick(() => {
    const range = document.createRange();
    const sel = window.getSelection();

    const textLength = el.textContent?.length || 0;
    if (position > textLength) {
      position = textLength;
    }

    let currentPos = 0;
    let targetNode: Node | null = null;
    let targetOffset = 0;

    const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
    let node: Node | null;

    while ((node = walker.nextNode())) {
      const nodeLength = node.textContent?.length || 0;

      if (currentPos + nodeLength >= position) {
        targetNode = node;
        targetOffset = position - currentPos;
        break;
      }
      currentPos += nodeLength;
    }

    if (targetNode) {
      range.setStart(targetNode, targetOffset);
      range.collapse(true);
      sel?.removeAllRanges();
      sel?.addRange(range);
    } else {
      range.selectNodeContents(el);
      range.collapse(false);
      sel?.removeAllRanges();
      sel?.addRange(range);
    }
  });
}

// 图片加载失败处理
const handleImageError = (event: Event) => {
  const img = event.target as HTMLImageElement;
  if (img) {
    img.style.display = 'none';
  }
};

// 初始化
onMounted(() => {
  if (editor.value) {
    let initialText = props.modelValue || '';
    // 初始化时判断是否为空
    isInputEmpty.value = !initialText || initialText.trim() === '';
    editor.value.textContent = initialText;

    document.addEventListener('selectionchange', selectionChangeHandler);
  }
})

// 选择变化处理函数
const selectionChangeHandler = () => {
  if (isEditorFocused.value && showSuggestions.value) {
    updateCursorPosition();
  }
};

// 清理资源
onBeforeUnmount(() => {
  document.removeEventListener('selectionchange', selectionChangeHandler);
});

// 外部值变化时更新编辑器内容
watch(() => props.modelValue, (newVal) => {
  if (editor.value && editor.value.textContent !== newVal) {
    let processedVal = newVal || '';
    // 更新空状态判断
    isInputEmpty.value = !processedVal || processedVal.trim() === '';
    
    editor.value.textContent = processedVal;

    nextTick(() => {
      setCursorPosition(editor.value, processedVal.length);
    });
  }
})

// 暴露公共方法
defineExpose({
  setContent: (value: string) => {
    if (editor.value) {
      let processedVal = value || '';
      // 更新空状态判断
      isInputEmpty.value = !processedVal || processedVal.trim() === '';
      editor.value.textContent = processedVal;

      nextTick(() => {
        setCursorPosition(editor.value, processedVal.length);
      });
    }
  },
  focus: () => {
    if (editor.value) {
      editor.value.focus();

      nextTick(() => {
        setCursorPosition(editor.value, editor.value.textContent?.length || 0);
      });
    }
  }
})
</script>

<style scoped>
/* 样式保持不变 */
.custom-mention {
  position: relative;
  width: 100%;
  min-height: 120px;
}

.mention-editor {
  --el-input-border-color: var(--el-border-color);
  --el-input-hover-border-color: var(--el-border-color-hover);
  --el-input-focus-border-color: var(--el-color-primary);
  --el-input-transition-duration: 0.2s;
  --el-input-bg-color: var(--el-fill-color-lighter);
  --el-input-text-color: var(--el-text-color-regular);
  --el-input-border-radius: 4px;
  --el-input-box-shadow: 0 0 0 2px var(--el-color-primary-light-5);
  width: 100%;
  min-height: 120px;
  padding: 12px 15px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--el-input-text-color);
  background-color: var(--el-input-bg-color);
  border: 1px solid var(--el-input-border-color);
  border-radius: var(--el-input-border-radius);
  transition:
    border-color var(--el-input-transition-duration),
    box-shadow var(--el-input-transition-duration);
  scrollbar-width: thin;
  scrollbar-color: var(--el-border-color) var(--el-fill-color-lighter);
  outline: none;
  will-change: contents;
  contain: content;
  overflow-y: auto;
  resize: vertical;
  box-sizing: border-box;

  white-space: pre-wrap;
  word-wrap: break-word;
  word-break: break-all;
  overflow-wrap: break-word;
  -webkit-hyphens: none;
  -moz-hyphens: none;
  hyphens: none;
}

.mention-editor:hover {
  border-color: var(--el-input-hover-border-color);
}

.mention-editor:focus {
  outline: 0;
  border-color: var(--el-input-focus-border-color);
  box-shadow: var(--el-input-box-shadow);
}

.mention-suggestions {
  max-height: 300px;
  overflow-y: auto;
  padding: 6px 0;
  box-sizing: border-box;
  background: var(--el-bg-color-overlay);
  border-radius: var(--el-border-radius-base);
}

.suggestion-item {
  padding: 8px 16px;
  cursor: pointer;
  transition: background 0.2s;
  display: flex;
  align-items: center;
  will-change: transform;
}

.suggestion-item:hover {
  background-color: var(--el-fill-color-light);
}

.suggestion-item.is-active {
  background-color: var(--el-fill-color-light);
}

.suggestion-content {
  display: flex;
  align-items: center;
  width: 100%;
  min-width: 200px;
}

.avatar {
  margin-right: 12px;
  flex-shrink: 0;
}

.info {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.value {
  font-weight: 600;
  margin-bottom: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.label {
  font-size: 0.85em;
  color: var(--el-text-color-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.loading-text,
.no-results {
  padding: 12px 16px;
  text-align: center;
  color: var(--el-text-color-secondary);
  font-size: 0.9em;
}

.mention-suggestions::-webkit-scrollbar {
  width: 4px;
}

.mention-suggestions::-webkit-scrollbar-track {
  background: transparent;
}

.mention-suggestions::-webkit-scrollbar-thumb {
  background: var(--el-border-color);
  border-radius: 2px;
}

.mention-editor::-webkit-scrollbar {
  width: 6px;
}

.mention-editor::-webkit-scrollbar-thumb {
  background-color: var(--el-border-color);
  border-radius: 3px;
}

.mention-editor::-webkit-scrollbar-thumb:hover {
  background-color: var(--el-text-color-placeholder);
}
</style>
